package com.mk.util.pay;

import act.app.ActionContext;
import act.app.App;
import act.event.ActEvent;
import act.event.EventBus;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mk.Starter;
import com.mk.enums.ErrorCode;
import com.mk.enums.GlobalValues;
import com.mk.exception.UserException;
import com.mk.properties.AppConfig;
import com.mk.util.*;
import org.apache.commons.collections.MapUtils;
import org.osgl.util.C;
import org.osgl.util.S;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

import static com.mk.util.HttpUtils.doPostSSL;


@SuppressWarnings("all")
public class UnionPayUtils extends PayUtils {
    //private final String host = "https://qr-test2.chinaums.com/";
    private final String host = AppConfig.union.host.get();
    private final String orderQueryUrl = host + "netpay-route-server/api/";//订单查询
    private final String orderRefundUrl = host + "netpay-route-server/api/";//订单退款
    private final String orderPayUrl =  host + "netpay-portal/webpay/pay.do";
    private final String closeOrderUrl = host + "netpay-route-server/api/";//关闭订单
    //企业转账地址
    private final String transfersUrl =  host+"netpay-route-server/api/";//企业转帐
    /**
     * 微信签名类型
     */
    private final String sign_type = "MD5";
//    private String m_id = AppConfig.union.m_id.get();
//    private String t_id = AppConfig.union.t_id.get();
//    private String msg_id = AppConfig.union.msg_id.get();
//    private String msg_src = AppConfig.union.msg_src.get();
//    private String sign_key = AppConfig.union.sign_key.get();

    private String m_id = "898340149000005";
    private String t_id = "88880001";
    private String msg_id = "3194";
    private String msg_src = "WWW.TEST.COM";
    private String sign_key = "fcAmtnx7MwismjWNhNKdHC44mNXtnEQeJkRrhKJwyrW2ysRR";
    private String info_des = "美多拼";
    private String msg_type="WXPay.jsPay";
    private String inst_mid="YUEDANDEFAULT";

    /**
     * 发送请求
     *
     * @param url
     * @param map
     * @return
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    private Map<String, String> doPostUrl(String url, Map<String, String> map) throws ParserConfigurationException, IOException, SAXException {
        //获取本地签名
        String postStr = getSign(map, "query");
        //向微信发起支付申请
        String result = HttpUtils.doPost(url,map);
        Starter.LOG.error("执行付款操作结果:" + JSON.toJSONString(result));
        //region 发事件,保存请求信息
        saveParamResult(url, map, result);
        //endregion 发事件,保存请求信息
        Map<String, String> payMap = PayUtils.getMapFromXML(result);
        if (!S.eq("SUCCESS", payMap.get("return_code"))) {
            throw new UserException(payMap.get("return_msg"));
        }
        if (!S.eq("SUCCESS", payMap.get("result_code"))) {
            throw new UserException(payMap.get("err_code_des"));
        }
        //将支付金额放入支付对象结果中
//        BigDecimal total_fee = MapUtil.getDg(map,"total_fee",BigDecimal.ZERO);
//        total_fee = total_fee.divide(new BigDecimal("100"));
//        payMap.put("total_fee",total_fee.toString());
        payMap.put("package", "prepay_id=" + payMap.get("prepay_id"));
        return payMap;
    }

    /**
     * 通过发事件,保存信息
     *
     * @param url
     * @param map
     * @param result
     */
    private void saveParamResult(String url, Map<String, String> map, String result) {
        //region 发事件,保存请求信息
        EventBus eventBus = App.instance().getInstance(EventBus.class);
        Map<String, Object> eventMap = new HashMap<>();
        eventMap.put("url", url);
        eventMap.put("params", map);
        eventMap.put("result", result);
        eventMap.put("paytype", "WX");
        eventBus.trigger("PAY_PARAM_RESULT", new ActEvent<>(eventMap));
        //endregion 发事件,保存请求信息
    }

    /**
     * 银联交易类接口基础参数
     *
     * @param url
     * @param map
     * @param result
     */
    private Map<String,String> getMustParam() {
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("msgSrc",msg_src);
        paramMap.put("mid",m_id);
        paramMap.put("tid",t_id);
        paramMap.put("instMid",inst_mid);
        return paramMap;
    }

    /**
     * 获取银联支付链接
     * total_fee传入是以元为单位
     *
     * @param paramMap         支付参数（body,out_trade_no,total_fee,ipAddress,userid,username）当trade_type=='NATIVE'时,必传 product_id
     * @return
     */
    private Map<String, String> payObjResult(Map<String, String> paramMap) {
        HashMap<String, String> map = new HashMap<>();
        String body = info_des + "-" + paramMap.get("body");
        body = body.replaceAll("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]", "");
        if (S.isNotEmpty(body) && body.length() > 40) {
            body = body.substring(0, 40);
        }
        map.put("msgId",msg_id);
        map.put("msgSrc",msg_src);
        map.put("msgType",msg_type);
        map.put("mid",m_id);
        map.put("tid",t_id);
        map.put("instMid",inst_mid);
        map.put("requestTimestamp", DateUtil.now());
        map.put("merOrderId",msg_id+MapUtil.getStr(paramMap,"out_trade_no"));
        map.put("attachedData",MapUtil.getStr(paramMap,"orderid"));
        map.put("orderDesc", body);
        map.put("originalAmount", new BigDecimal(paramMap.get("originalprice")).multiply(new BigDecimal(100)).intValue() + "");
        map.put("totalAmount", new BigDecimal(paramMap.get("total_fee")).multiply(new BigDecimal(100)).intValue() + "");

        map.put("returnUrl",MapUtil.getStr(paramMap,"resulturl"));
        map.put("notifyUrl",AppConfig.union.callback.get());
        map.put("systemId",S2.UUID());
        map.put("signType",sign_type);
        map.put("subOpenId",MapUtil.getStr(paramMap,"openid"));
        String payurl=orderPayUrl+"?"+getSign(map,"query");

        return C.Map("payurl",payurl,"paytype",GlobalValues.PAY_TYPE_UNION.value());
    }

    /**
     * 获取支付对象 APP
     *
     * @param paramMap 支付参数（body,out_trade_no,total_fee,ipAddress,userid,username）
     * @return
     */
    @Override
    public Map<String, String> getPayObject(Map<String, String> paramMap) {
        return payObjResult(paramMap);
    }

    /**
     * 获取支付对象 公众号
     *
     * @param paramMap 支付参数（body,out_trade_no,total_fee,ipAddress,userid,username）
     * @return
     */
    @Override
    public Map<String, String> getPayObjectGzh(Map<String, String> paramMap) {
        return null;
    }

    /**
     * 获取支付对象 H5
     *
     * @param paramMap 支付参数（body,out_trade_no,total_fee,ipAddress,userid,username）
     * @return
     */
    @Override
    public Map<String, String> getPayObjecth5(Map<String, String> paramMap) {
        return null;
    }

    /**
     * 获取支付对象 二维码链接
     *
     * @param paramMap 支付参数（body,out_trade_no,total_fee,ipAddress,userid,username）product_id
     * @return
     */
    @Override
    public String getPayCodeUrl(Map<String, String> paramMap) {
        return null;
    }

    /*
     * 查询订单支付情况
     * */
    @Override
    public Map<String, String> getOrderInfo(String payid) {
        Map<String, String> queryMap = getMustParam();
        queryMap.put("merOrderId", msg_id+payid);
        queryMap.put("msgType","query");
        queryMap.put("requestTimestamp",DateUtil.now());
        String sign = getSign(queryMap, "sign");
        queryMap.put("sign",sign);
        String result = HttpUtils.doPost(this.orderQueryUrl, JSONObject.toJSONString(queryMap));
        try {
            return JSONObject.parseObject(result,Map.class);
        } catch (Exception ex) {
            throw new UserException("网络错误，请稍后重试！");
        }
    }

    @Override
    public boolean closeOrder(String payid) {
        return false;
    }

    /**
     * 验证订单支付状态
     */
    @Override
    public Map<String, String> validatePayidState(String payid) throws UserException {
        Map<String, String> map = getOrderInfo(payid);
        String return_code = map.get("status");
        Map jsonObj = Redis.payDb.getBucket(payid, HashMap.class).get();
        jsonObj.put("signVerified", "false");
        jsonObj.put("result_code", map.get("status"));
        jsonObj.put("time_end", map.get("payTime"));
        jsonObj.put("amount", new BigDecimal(MapUtil.getStr(map, "totalAmount")).divide(new BigDecimal("100"), BigDecimal.ROUND_HALF_UP, 2));
        if ("TRADE-SUCCESS".equals(return_code)) {
            ;//||trade_state.contains("REFUND");
            jsonObj = JSON.parseObject(map.get("attach"), HashMap.class);
            jsonObj.put("flag", "true");
        } else {
            jsonObj = new HashMap<>();
            jsonObj.put("flag", "false");
        }
        return jsonObj;
    }

    /**
     * 退款
     *
     * @param paramMap (orderid:订单id,orderamount:退款金额)
     * @return
     * @throws UserException
     */
    @Override
    public boolean refundOrder(Map<String, String> paramMap) throws UserException {
        Map<String, String> map = getMustParam();
        map.put("msgType","refund");
        map.put("requestTimestamp",DateUtil.now());
        map.put("merOrderId",msg_id+MapUtil.getStr(paramMap,"orderid"));
        BigDecimal refundAmount=new BigDecimal(MapUtil.getStr(paramMap,"orderamount"));
        map.put("refundAmount",refundAmount.multiply(new BigDecimal(100)).setScale(0).toString());
        map.put("refundOrderId",msg_id+MapUtil.getStr(paramMap,"refundid"));
        String reason = paramMap.get("reason");
        if (S.isEmpty(reason)) {
            reason = "退款";
        }
        map.put("refundDesc", info_des + "-" + reason);
        String sign = getSign(map, "sign");
        map.put("sign",sign);
        String result = "";
        try {
            result = HttpUtils.doPost(this.orderRefundUrl, JSONObject.toJSONString(map));
        } catch (Exception ex) {
            result = ex.getMessage();
            throw new UserException(ex.getMessage());
        } finally {
            //saveParamResult(this.orderRefundUrl, map, result);
        }
        try {
            Map<String, String> resultMap = JSONObject.parseObject(result,Map.class);
            if (S.neq(resultMap.get("errCode"),GlobalValues.WEIXINRESULT_SUCCESS.value())) {
                throw new UserException(resultMap.get("errMsg"));
            }
            if (S.eq(getSign(resultMap, "sign"), resultMap.get("sign"))) {
                throw new UserException("返回结果验证签名失败");
            }
            return true;
        } catch (Exception ex) {
            throw new UserException(ex.getMessage());
        }
    }

    /**
     * 签名
     */
    @Override
    public String getSign(Map<String, String> map, String strType) {
        List list = new ArrayList<>(map.keySet());
        String apiKey = msg_id;
        Collections.sort(list);
        StringBuilder queryString = new StringBuilder();
        StringBuilder queryStringsign = new StringBuilder();
        for (Object aList : list) {
            if (S.isNotEmpty(MapUtil.getStr(map,aList))) {
                if (aList.equals("sign")) {
                    continue;
                }
                queryString.append(aList).append("=").append(S.urlEncode(MapUtil.getStr(map,aList)));
                queryString.append("&");
                queryStringsign.append(aList).append("=").append(S.urlDecode(MapUtil.getStr(map,aList)));
                queryStringsign.append("&");
            }
        }
        String str=queryStringsign.substring(0,queryStringsign.length()-1);
        String sign = EncyUtils.MD5(str,sign_key).toUpperCase();
        String result = "";
        switch (strType) {
            case "sign":
                result = sign;
                break;
            case "query":
                queryString.append("sign=").append(sign);
                result = queryString.toString();
                break;
        }
        return result;
    }


    @Override
    public Map<String, Object> selTransfer(Map<String, Object> map) {
        return null;
    }

    @Override
    public String goWallet(Map<String, Object> map) {
        return null;
    }


    @Override
    public String getSignown(Map<String, Object> map, String strType) {
        return null;
    }

    @Override
    public Map<String, String> transfer(Map<String, String> map) throws Exception {
        return null;
    }

    /**
     * 回调数据验证及处理
     *
     * @param map
     * @return
     */
    @Override
    public Map<String, Object> payCallback(Map<String, String> params, ActionContext context) {
        Map<String, Object> param = new HashMap<>();
        String sign=getSign(params,"sign");
        try {
            String payid = params.get("merOrderId").substring(4);
            param.put("payid", payid);
            String return_code = params.get("status");
            Map jsonObj = Redis.payDb.getBucket(payid, HashMap.class).get();
            param.put("signVerified", "false");
            param.put("result_code", params.get("status"));
            param.put("time_end", params.get("payTime"));
            param.put("amount", new BigDecimal(MapUtil.getStr(params, "totalAmount")).divide(new BigDecimal("100"), BigDecimal.ROUND_HALF_UP, 2));
            jsonObj.forEach((k, v) -> param.put(k + "", v));
            if ("TRADE_SUCCESS".equals(return_code) && getSign(params, "sign").equals(params.get("sign"))) {
                param.put("signVerified", "true");
            } else {//验证失败
                throw new UserException("支付回调验证失败");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return param;
    }

}
